package cn.ahaoweb.drule.core.compile;

import cn.ahaoweb.drule.core.compile.enums.ConditionFieldTypeEnum;
import cn.ahaoweb.drule.core.compile.enums.ConditionOperate;
import cn.ahaoweb.drule.core.compile.exception.NotSupportOperatorException;
import cn.ahaoweb.drule.core.compile.structure.DruleBlock;
import cn.ahaoweb.drule.core.model.enums.NodeType;

import java.util.Objects;

/**
 * @Name: 条件运算语句生成器
 * @Description:
 * @Author: wangzhonghao
 * @Date: 2025/2/7 16:51
 */
public abstract class Operator {

    /**
     * 编译语句
     *
     * @param condition
     * @return
     */
    public String compile(DruleBlock.Condition condition) {
        if (support(condition)) {
            String s = doCompile(condition);
            if (s != null) {
                return s;
            }
        }
        throw new NotSupportOperatorException("条件运算符【" + ConditionOperate.getInstance(getClass()).getChinese() + "】" +
                "不支持数据类型：" + condition.getFieldInfo().getDataType() + "（" + condition.getFieldInfo().getFieldCode() + "）");
    }

    /**
     * 判断是否支持该数据类型
     *
     * @param condition
     * @return
     */
    public boolean support(DruleBlock.Condition condition) {
        return true;
    }

    /**
     * 预处理字符串，支持"插值表达式": ${}
     * <pre>
     *     123 -> "123"
     *     "123 -> "123"
     *     123" -> "123"
     *     "123" -> "123"
     *     ${getCode()} -> getCode()
     * </pre>
     *
     * @param value
     * @return
     */
    public static String preprocessString(String value) {
        if ("null".equals(value)) {
            return "null";
        }
        if (value.startsWith("${") && value.endsWith("}")) {
            int i = value.indexOf("${");
            int j = value.lastIndexOf("}");
            return value.substring(i + 2, j);
        } else {
            if (!value.startsWith("\"")) {
                value = "\"" + value;
            }
            if (!value.endsWith("\"")) {
                value = value + "\"";
            }
        }
        return value;
    }

    public static String preprocessCharacter(String value) {
        if ("null".equals(value)) {
            return "null";
        }
        if (value.startsWith("${") && value.endsWith("}")) {
            int i = value.indexOf("${");
            int j = value.lastIndexOf("}");
            return value.substring(i + 2, j);
        } else {
            if (!value.startsWith("'")) {
                value = "'" + value;
            }
            if (!value.endsWith("'")) {
                value = value + "'";
            }
        }
        return value;
    }

    public static String preprocess(String value) {
        if ("null".equals(value)) {
            return "null";
        }
        if (value.startsWith("${") && value.endsWith("}")) {
            int i = value.indexOf("${");
            int j = value.lastIndexOf("}");
            return value.substring(i + 2, j);
        }
        return value;
    }

    /**
     * 根据条件对给定的值进行处理。
     *
     * @param condition  条件对象
     * @param judgeValue 待处理的字符串值
     * @return 处理后的字符串
     */
    public String processValue(DruleBlock.Condition condition, String judgeValue) {
        String str;
        NodeType kind = condition.getFieldInfo().getKind();
        if (equal(String.class, condition.getFieldInfo().getDataType())
                || NodeType.STRING.equals(kind)) {
            str = preprocessString(judgeValue);
        } else if (NodeType.CHAR.equals(kind)) {
            str = preprocessCharacter(judgeValue);
        } else {
            str = preprocess(judgeValue);
        }
        return str;
    }


    public String getSymbol() {
        return ConditionOperate.getInstance(this.getClass()).getSymbol();
    }

    protected abstract String doCompile(DruleBlock.Condition condition);

    // 等于
    public static class Eq extends Operator {

        @Override
        public String doCompile(DruleBlock.Condition condition) {
            String fieldCode = condition.getFieldInfo().getFieldCode();
            String judgeValue = condition.getJudgeValue();
            String s = processValue(condition, judgeValue);
            return new StringBuilder()
                    .append(fieldCode)
                    .append(" ")
                    .append(getSymbol())
                    .append(" ")
                    .append(s)
                    .toString();
        }

    }

    // 不等于
    public static class Neq extends Eq {
    }

    // 大于小于父类
    private static class GL extends Operator {
        @Override
        public String doCompile(DruleBlock.Condition condition) {
            String fieldCode = condition.getFieldInfo().getFieldCode();
            String judgeValue = condition.getJudgeValue();
            return new StringBuilder()
                    .append(fieldCode)
                    .append(" ")
                    .append(getSymbol())
                    .append(" ")
                    .append(processValue(condition, judgeValue))
                    .toString();
        }

        @Override
        public boolean support(DruleBlock.Condition condition) {
            NodeType kind = condition.getFieldInfo().getKind();
            return NodeType.NUMBER.equals(kind)
                    || NodeType.OTHER.equals(kind)
                    || kind == null;
        }

        @Override
        public String processValue(DruleBlock.Condition condition, String judgeValue) {
            return preprocess(judgeValue);
        }
    }

    // 小于
    public static class Lt extends GL {
    }

    // 小于等于
    public static class Lte extends GL {
    }

    // 大于
    public static class Gt extends GL {
    }

    // 大于等于
    public static class Gte extends GL {
    }

    // 包含
    private static class Contains extends Operator {


        @Override
        protected String doCompile(DruleBlock.Condition condition) {
            return null;
        }

        @Override
        public boolean support(DruleBlock.Condition condition) {
            NodeType kind = condition.getFieldInfo().getKind();
            if (kind != null) {
                if (NodeType.STRING.equals(kind)
                        || NodeType.isList(kind)) {
                    return true;
                }
                // 其他类型不支持contains
                return false;
            } else {
                return true;
            }
        }

        @Override
        public String processValue(DruleBlock.Condition condition, String judgeValue) {
            NodeType kind = condition.getFieldInfo().getKind();
            if (equal(String.class, condition.getFieldInfo().getDataType())
                    || NodeType.STRING.equals(kind)
                    || NodeType.LIST_OF_STRING.equals(kind)) {
                return preprocessString(judgeValue);
            } else {
                return preprocess(judgeValue);
            }
        }

    }

    // 左包含
    public static class LeftContains extends Contains {

        @Override
        protected String doCompile(DruleBlock.Condition condition) {
            String fieldCode = condition.getFieldInfo().getFieldCode();
            String judgeValue = condition.getJudgeValue();
            return new StringBuilder()
                    .append(fieldCode)
                    .append(" ")
                    .append(getSymbol())
                    .append(" ")
                    .append(processValue(condition, judgeValue))
                    .toString();
        }

    }

    // 右包含
    public static class RightContains extends LeftContains {
        @Override
        protected String doCompile(DruleBlock.Condition condition) {
            String fieldCode = condition.getFieldInfo().getFieldCode();
            String judgeValue = condition.getJudgeValue();
            return new StringBuilder()
                    .append(processValue(condition, judgeValue))
                    .append(" ")
                    .append(getSymbol())
                    .append(" ")
                    .append(fieldCode)
                    .toString();
        }
    }

    // 左包含
    public static class LeftNotContains extends LeftContains {
    }

    // 右不包含
    public static class RightNotContains extends RightContains {
    }

    // 存在于
    public static class In extends Operator {

        @Override
        protected String doCompile(DruleBlock.Condition condition) {
            String fieldCode = condition.getFieldInfo().getFieldCode();
            String judgeValue = condition.getJudgeValue().trim();
            return new StringBuilder()
                    .append(fieldCode)
                    .append(" ")
                    .append(getSymbol())
                    .append(" ")
                    .append(processValue(condition, judgeValue))
                    .toString();
        }

        @Override
        public String processValue(DruleBlock.Condition condition, String judgeValue) {
            String[] elements = judgeValue.split(",");
            StringBuilder v = new StringBuilder();
            if (elements.length > 1) {
                for (int i = 0; i < elements.length; i++) {
                    v.append(super.processValue(condition, elements[i])).append(",");
                }
            } else if (elements.length == 1) {
                v.append(super.processValue(condition, elements[0])).append(",");
            } else {
                throw new NullPointerException("判断值不能为空");
            }
            v.deleteCharAt(v.length() - 1);
            return "(" + v + ")";
        }
    }

    // 不存在于
    public static class NotIn extends In {
    }

    // 正则匹配
    public static class Matches extends Operator {

        @Override
        protected String doCompile(DruleBlock.Condition condition) {
            String fieldCode = condition.getFieldInfo().getFieldCode();
            String judgeValue = condition.getJudgeValue();
            return new StringBuilder()
                    .append(fieldCode)
                    .append(" ")
                    .append(getSymbol())
                    .append(" ")
                    .append(preprocessString(judgeValue))
                    .toString();
        }

        @Override
        public boolean support(DruleBlock.Condition condition) {
            if (equal(String.class, condition.getFieldInfo().getDataType())
                    || NodeType.STRING.equals(condition.getFieldInfo().getKind())) {
                return true;
            }
            return false;
        }
    }

    // 正则不匹配
    public static class NotMatches extends Matches {
    }

    /**
     * 判断类型名称是否相等
     *
     * @param c
     * @param s
     * @return
     */
    public static boolean equal(Class<?> c, String s) {
        return Objects.equals(s, c.getCanonicalName());
    }

}
